import FormData from 'form-data'
import { isBlob, isPlainObject } from 'es-toolkit'
import { isArray } from 'es-toolkit/compat'
import { ApiRequestOptions } from './AxiosRequestConfig'

export function filterParams(data: unknown) {
  if (isPlainObject(data)) {
    for (const key in data) {
      let dk = data[key]
      if (isPlainObject(dk)) {
        dk = filterParams(dk)
      } else if (isArray(dk)) {
        dk = dk.map((item: unknown) => {
          return filterParams(item)
        })
      } else {
        if (
          Object.prototype.hasOwnProperty.call(data, key) &&
          (dk === null ||
            dk === 'null' ||
            dk === undefined ||
            dk === 'undefined' ||
            key.startsWith('__'))
        ) {
          delete data[key]
        }
      }
    }
  }
  return data
}

export function getUrl(options: ApiRequestOptions) {
  return (
    options.url?.replace(/{(.*?)}/g, (substring: string, group: string) => {
      if (Object.prototype.hasOwnProperty.call(options.path, group)) {
        return encodeURI(String(options.path?.[group]))
      }
      return substring
    }) || ''
  )
}

export function getFormData(options: ApiRequestOptions): FormData | undefined {
  if (options.formData) {
    const formData = new FormData()

    const process = (key: string, value: unknown) => {
      if (isString(value) || isBlob(value)) {
        formData.append(key, value)
      } else {
        formData.append(key, JSON.stringify(value))
      }
    }

    Object.entries(options.formData)
      .filter(([_, value]) => isDefined(value))
      .forEach(([key, value]) => {
        if (Array.isArray(value)) {
          value.forEach((v) => process(key, v))
        } else {
          process(key, value)
        }
      })

    return formData
  }
  return undefined
}

export const isDefined = <T>(
  value: T | null | undefined,
): value is Exclude<T, null | undefined> => {
  return value !== undefined && value !== null
}

export const isString = (value: unknown): value is string => {
  return typeof value === 'string'
}

export const isStringWithValue = (value: unknown): value is string => {
  return isString(value) && value !== ''
}

export const isFormData = (value: unknown): value is FormData => {
  return value instanceof FormData
}

export const base64 = (str: string): string => {
  try {
    return btoa(str)
  } catch {
    return Buffer.from(str).toString('base64')
  }
}
